package com.heima.search.service.impl;

import com.heima.common.exception.CustomException;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.search.dtos.UserSearchDto;
import com.heima.search.service.SearchService;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author brianxia
 * @version 1.0
 * @date 2022-09-20 11:22
 */
@Service
@Slf4j
public class SearchServiceImpl implements SearchService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Override
    public List<Map> search(UserSearchDto dto) {

        //1.构建查询条件
        try{
            SearchRequest request = new SearchRequest();
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            //查询条件
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            //must should must_not filter
            //must(and) should(or) 需要计算算分，算分排序有效 分词查询
            //must_not(不...) filter(直接条件)不计算算分，使用缓存性能比较高 非分词查询

            //must算分 + 对标题和内容进行分词查询，or连接代表只要有一个满足数据保存下来
            boolQueryBuilder.must(QueryBuilders.queryStringQuery(dto.getSearchWords()).field("title").field("content")
                    .defaultOperator(Operator.OR));
            //filter不计算算分+range查询对时间进行过滤，满足小于当前这一页最小时间
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("publishTime").lt(dto.getMinBehotTime().getTime()));

            searchSourceBuilder.query(boolQueryBuilder);
            //类似mysql limit 0,10 分页
            searchSourceBuilder.from(0);
            searchSourceBuilder.size(dto.getPageSize());
            //排序
            searchSourceBuilder.sort("publishTime", SortOrder.DESC);
            //高亮 放三要素 高亮字段 高亮前缀 高亮后缀
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.field("title");
            highlightBuilder.preTags("<font style='color: red; font-size: inherit;'>");
            highlightBuilder.postTags("</font>");
            searchSourceBuilder.highlighter(highlightBuilder);

            request.source(searchSourceBuilder);
            SearchResponse search = restHighLevelClient.search(request, RequestOptions.DEFAULT);

            //2.解析响应结果
            List<Map> maps = new ArrayList<>();
            SearchHit[] hits = search.getHits().getHits();
            for (SearchHit hit : hits) {
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                //兜底方案 给h_title默认值
                sourceAsMap.put("h_title",sourceAsMap.get("title"));
                //处理高亮
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                HighlightField title = highlightFields.get("title");
                if(title != null){
                    Text[] fragments = title.getFragments();
                    if(fragments != null && fragments.length > 0){
                        Text fragment = fragments[0];
                        if(fragment != null){
                            String str = fragment.string();
                            sourceAsMap.put("h_title",str);
                        }
                    }
                }
                maps.add(sourceAsMap);
            }
            return maps;
        }catch (Exception e){
            log.error("查询关键字错误",e);
            throw new CustomException(AppHttpCodeEnum.SERVER_ERROR);
        }

    }
}
